' ***********************************************************************
' Assembly         : Ioc
' Author           : Tim Ford
' Created          : 10-02-2013
'
' Last Modified By : Tim Ford
' Last Modified On : 10-02-2013
' ***********************************************************************
' <copyright file="SingleInstanceCached.vb" company="Red Baron Solutions">
'     Red Baron Solutions. All rights reserved.
' </copyright>
' <summary></summary>
' ***********************************************************************
Imports System.CodeDom.Compiler
Imports System.Reflection
Imports System.Globalization


Namespace Ioc
    ''' <summary>
    ''' Class SingleInstance.
    ''' </summary>
    Friend Class SingleInstanceCached
        Inherits BaseFactory

        Shared Sub New()
            'Load 
            Dim cache As System.Runtime.Caching.ObjectCache = System.Runtime.Caching.MemoryCache.Default

        End Sub
        ''' <summary>
        ''' The m_instance
        ''' </summary>
        Private ReadOnly m_Instance As Object
        Private ReadOnly m_BaseType As Type
        Private ReadOnly m_InstanceType As Type
        ''' <summary>
        ''' Initializes a new instance of the <see cref="SingleInstance"/> class.
        ''' </summary>
        ''' <param name="instance">The instance.</param>
        Public Sub New(baseType As Type, instance As Object)
            m_Instance = instance
            m_InstanceType = instance.GetType
            m_BaseType = baseType
            FillMethods()
            m_GeneratedType = DynamicLoadType()
            If m_GeneratedType IsNot Nothing Then
                m_SeveredInstance = ObjectFactory.Create(m_GeneratedType, m_Instance)
            Else
                m_SeveredInstance = m_Instance
            End If

        End Sub
        ''' <summary>
        ''' Initializes a new instance of the <see cref="SingleInstance"/> class.
        ''' </summary>
        Public Sub New(baseType As Type, instanceType As Type)
            m_BaseType = baseType
            m_InstanceType = instanceType
            FillMethods()
            m_GeneratedType = DynamicLoadType()
            If m_GeneratedType IsNot Nothing Then
                m_SeveredInstance = ObjectFactory.Create(m_GeneratedType)
            Else
                m_SeveredInstance = ObjectFactory.Create(m_BaseType)
            End If
        End Sub
        Private Sub New()
            
        End Sub
       
   

        ''' <summary>
        ''' Gets or sets the default time span.	
        ''' </summary>
        ''' <value>The default time span.</value>
        ''' <remarks></remarks>
        Public Property DefaultTimeSpan() As TimeSpan
            Get
                If m_DefaultTimeSpan = Nothing Then
                    m_DefaultTimeSpan = New TimeSpan(0, 10, 0)
                End If
                Return m_DefaultTimeSpan
            End Get
            Set(ByVal value As TimeSpan)
                If m_DefaultTimeSpan = value Then
                    Return
                End If
                m_DefaultTimeSpan = value
            End Set
        End Property
        Private m_DefaultTimeSpan As TimeSpan

        Private Sub FillMethods()
            For Each mi As MethodInfo In m_BaseType.GetMethods
                Dim item As New DataObjects.MethodDefinition
                Methods.Add(item)
                item.Fill(mi, m_BaseType.Name, m_InstanceType)
            Next

            Dim map As InterfaceMapping = m_InstanceType.GetInterfaceMap(m_BaseType)
            For x As Integer = 0 To map.InterfaceMethods.Count - 1
                Dim interfaceMethod As MethodInfo = map.InterfaceMethods(x)
                Dim foundMethod As MethodInfo = map.TargetMethods(x)
                Dim methodDefinition = Methods.FirstOrDefault(Function(meth) String.Compare(meth.MethodName, interfaceMethod.Name, True) = 0)
                methodDefinition.InstanceMethodName = foundMethod.Name
            Next


            Methods.ToList.ForEach(Sub(Item)
                                       If Item.MethodName.StartsWith("get_", StringComparison.CurrentCulture) Then
                                           Dim newMethodNaem As String = Item.MethodName.Replace("get_", "")
                                           Item.InstanceMethodName = Item.InstanceMethodName.Replace("get_", "")
                                           Dim foundMethod As DataObjects.MethodDefinition = Methods.FirstOrDefault(Function(propItem) String.Compare(propItem.MethodName, newMethodNaem, True) = 0)
                                           If foundMethod IsNot Nothing Then
                                               foundMethod.CanRead = True
                                               Methods.Remove(Item)
                                           Else
                                               Item.MethodName = newMethodNaem
                                               Item.CanRead = True
                                               Item.IsProperty = True
                                           End If
                                       End If
                                       If Item.MethodName.StartsWith("set_", StringComparison.CurrentCulture) Then
                                           Dim newMethodNaem As String = Item.MethodName.Replace("set_", "")
                                           Item.InstanceMethodName = Item.InstanceMethodName.Replace("set_", "")
                                           Dim foundMethod As DataObjects.MethodDefinition = Methods.FirstOrDefault(Function(propItem) String.Compare(propItem.MethodName, newMethodNaem, True) = 0)
                                           If foundMethod IsNot Nothing Then
                                               foundMethod.CanWrite = True
                                               Methods.Remove(Item)
                                           Else
                                               Item.MethodName = newMethodNaem
                                               Item.CanWrite = True
                                               Item.IsProperty = True
                                           End If

                                       End If

                                   End Sub)


        End Sub

        Private Function Methods() As List(Of DataObjects.MethodDefinition)
            If m_Methods Is Nothing Then
                m_Methods = New List(Of DataObjects.MethodDefinition)
            End If
            Return m_Methods
        End Function
        Private m_Methods As List(Of DataObjects.MethodDefinition)

        Private Function Build() As String
            Dim sb As New System.Text.StringBuilder
            With sb
                .Append("Namespace Dynamic.Cache").AppendLine()
                .AppendFormat(CultureInfo.CurrentCulture, "    Public Class {0}", m_BaseType.Name).AppendLine()
                .AppendFormat(CultureInfo.CurrentCulture, "        Implements {0}", m_BaseType.FullName).AppendLine()
                If m_Instance IsNot Nothing Then
                    .AppendFormat(CultureInfo.CurrentCulture, "        Public Sub New(instance As {0})", m_BaseType.FullName).AppendLine()
                    .Append("            m_Instance = instance").AppendLine()
                    .Append("        End Sub").AppendLine()
                    .AppendFormat(CultureInfo.CurrentCulture, "        Private m_Instance As {0}", m_BaseType.FullName).AppendLine()
                Else
                    .Append("        Public Sub New()").AppendLine()
                    .AppendFormat("            m_Lazy = New System.Lazy(Of {0})", m_InstanceType.FullName).AppendLine()
                    .Append("        End Sub").AppendLine()
                    .AppendFormat("        Private m_Lazy As System.Lazy(Of {0})", m_InstanceType.FullName).AppendLine()
                End If
            
                .AppendFormat("        Private Function GetInstance() As {0}", m_BaseType.FullName).AppendLine()
                If m_Instance IsNot Nothing Then
                    .Append("            Return m_Instance").AppendLine()
                Else
                    .Append("            Return m_Lazy.Value").AppendLine()
                End If
                .Append("        End Function").AppendLine()

                Methods.ForEach(Sub(mi)
                                    If mi.IsProperty Then
                                        Dim propertyInfo As PropertyInfo = m_InstanceType.GetProperty(mi.InstanceMethodName)
                                        If propertyInfo.HasAttribute(Of Attributes.DoNotCacheMethodAttribute)() Then
                                            .Append(BuildMethodProperty(mi))
                                        Else
                                            propertyInfo = m_BaseType.GetProperty(mi.MethodName)
                                            If propertyInfo.HasAttribute(Of Attributes.DoNotCacheMethodAttribute)() Then
                                                .Append(BuildMethodProperty(mi))
                                            Else
                                                .Append(BuildMethodCacheProperty(mi))
                                            End If
                                        End If

                                    Else
                                        If mi.ReturnType IsNot Nothing AndAlso mi.ReturnType IsNot GetType(Void) Then
                                            Dim method As MethodInfo = m_InstanceType.GetMethod(mi.InstanceMethodName)
                                            If method.HasAttribute(Of Attributes.DoNotCacheMethodAttribute)() Then
                                                .Append(GetFunction(mi))
                                            Else
                                                If mi.Method.HasAttribute(Of Attributes.DoNotCacheMethodAttribute)() Then
                                                    .Append(GetFunction(mi))
                                                Else
                                                    .Append(GetFunctionCache(mi))
                                                End If
                                            End If

                                        Else
                                            .Append(GetSub(mi))
                                        End If
                                    End If
                                End Sub)
                .Append("    End Class").AppendLine()
                .Append("End Namespace").AppendLine()
            End With
            Return sb.ToString
        End Function

        Private Function DynamicLoadType() As Type
            Try
                Dim providerOptions As New Dictionary(Of String, String)()
                providerOptions.Add("CompilerVersion", "v4.0")
                Using myCodeProvider = New VBCodeProvider(providerOptions)
                    Dim code As String = Build()
                    Dim results = myCodeProvider.CompileAssemblyFromSource(SetCompilerOptions, code)
                    If Not results.Errors.HasErrors Then
                        Dim copierType As Type = results.CompiledAssembly.[GetType](String.Format(CultureInfo.CurrentCulture, "Dynamic.Cache.{0}", m_BaseType.Name))

                        Return copierType
                    Else
                        Return Nothing
                    End If

                End Using
            Catch ex As Exception
                Return Nothing
            End Try
        End Function

        Private Shared Function SetCompilerOptions() As CompilerParameters
            Dim cp = New CompilerParameters()
            Dim assemblies As List(Of String) = (From a In AppDomain.CurrentDomain.GetAssemblies() Where a.IsDynamic = False Select a.Location).ToList
            Dim assemblyList As New System.Text.StringBuilder
            For Each assemblyItem As String In assemblies
                Try
                    If Not String.IsNullOrWhiteSpace(assemblyItem) Then
                        cp.ReferencedAssemblies.Add(assemblyItem)
                        assemblyList.Append(assemblyItem)
                    End If
                Catch ex As Exception
                    'do nothing just skip
                End Try
            Next

            cp.GenerateInMemory = False
            cp.IncludeDebugInformation = False
            cp.TreatWarningsAsErrors = False
            cp.WarningLevel = 3
            cp.CompilerOptions = "/optimize"
            Return cp
        End Function


        Private Function GetFunctionCache(method As DataObjects.MethodDefinition) As String
            Dim sb As New System.Text.StringBuilder
            sb.AppendFormat("        Public Function {1}({3}) As {2} Implements {0}.{1}", m_BaseType.FullName, method.MethodName, method.ReturnType.Name, BuildMethodSignature(method)).AppendLine()
            GetCacheKey(method, sb)
            SetCacheInstance(method, sb)
            sb.Append("            Return cacheInstance").AppendLine()
            sb.Append("        End Function").AppendLine()

            Return sb.ToString()
        End Function

        Private Function BuildMethodCacheProperty(method As DataObjects.MethodDefinition) As String
            Dim sb As New System.Text.StringBuilder

            If method.CanRead And method.CanWrite Then
                StandardProperty(method, sb)
            Else
                If method.CanWrite Then
                    WriteOnlyProperty(method, sb)
                Else
                    ReadOnlyProperty(method, sb)
                End If
            End If

            Return sb.ToString
        End Function

        Private Sub StandardProperty(ByVal method As DataObjects.MethodDefinition, ByVal sb As System.Text.StringBuilder)
            sb.AppendFormat("        Public Property {1}({3}) As {2} Implements {0}.{1}", m_BaseType.FullName, method.MethodName, method.ReturnType.Name, BuildMethodSignature(method)).AppendLine()
            sb.Append("            Get").AppendLine()
            GetCacheKey(method, sb)
            SetCacheInstance(method, sb)
            sb.Append("            Return cacheInstance").AppendLine()
            sb.Append("            End Get").AppendLine()
            sb.AppendFormat(CultureInfo.CurrentCulture, "            Set(value As {0})", method.ReturnType.Name).AppendLine()
            sb.AppendFormat("                GetInstance.{0}({1}) = Value", method.MethodName, BuildSignature(method)).AppendLine()
            ResetCache(method, sb)

            sb.Append("            End Set").AppendLine()

            sb.Append("        End Property").AppendLine()
        End Sub

        Private Sub ReadOnlyProperty(ByVal method As DataObjects.MethodDefinition, ByVal sb As System.Text.StringBuilder)
            sb.AppendFormat("        Public ReadOnly Property {1}({3}) As {2} Implements {0}.{1}", m_BaseType.FullName, method.MethodName, method.ReturnType.Name, BuildMethodSignature(method)).AppendLine()
            sb.Append("            Get").AppendLine()
            GetCacheKey(method, sb)
            SetCacheInstance(method, sb)
            sb.Append("            Return cacheInstance").AppendLine()
            sb.Append("            End Get").AppendLine()
            sb.Append("        End Property").AppendLine()
        End Sub

        Private Sub WriteOnlyProperty(ByVal method As DataObjects.MethodDefinition, ByVal sb As System.Text.StringBuilder)
            sb.AppendFormat("        Public WriteOnly Property {1}({3}) As {2} Implements {0}.{1}", m_BaseType.FullName, method.MethodName, method.Signature(0).Type.FullName, BuildWriteOnlyPropertyMethodSignature(method)).AppendLine()
            sb.AppendFormat("            Set(value As {0})", method.Signature(0).Type.FullName).AppendLine()
            sb.AppendFormat("                GetInstance.{0}({1}) = Value", method.MethodName, BuildWriteOnlyPropertySignature(method)).AppendLine()
            ResetCache(method, sb)
            sb.Append("            End Set").AppendLine()
            sb.Append("        End Property").AppendLine()
        End Sub

        Private Sub GetCacheKey(ByVal method As DataObjects.MethodDefinition, ByVal sb As System.Text.StringBuilder)
            If method.Signature.Count > 0 Then
                sb.AppendFormat(CultureInfo.CurrentCulture, "            Dim cacheName As String = {0}", BuildCacheKey(method, method.MethodName)).AppendLine()
            Else
                sb.AppendFormat("            Dim cacheName As String =""{0}{1}ConfigKey""", m_BaseType.FullName, method.MethodName).AppendLine()
            End If
        End Sub

        Private Sub SetCacheInstance(ByVal method As DataObjects.MethodDefinition, ByVal sb As System.Text.StringBuilder)
            sb.Append("            Dim cache As System.Runtime.Caching.ObjectCache = System.Runtime.Caching.MemoryCache.Default").AppendLine()
            Dim casting As String = String.Format(method.ReturnType.GetCastingString(), "cache(cacheName)")
            sb.AppendFormat(CultureInfo.CurrentCulture, "            Dim cacheInstance As {0} = {1}", method.ReturnType.Name, casting).AppendLine()

            sb.Append("            If cacheInstance Is Nothing Then").AppendLine()
            Dim methodInfo As MethodInfo = m_InstanceType.GetMethod(method.InstanceMethodName)
            If methodInfo IsNot Nothing AndAlso methodInfo.HasAttribute(Of Attributes.MethodCacheTimeAttribute)() Then

                Dim cacheTime As Attributes.MethodCacheTimeAttribute = methodInfo.GetAttribute(Of Attributes.MethodCacheTimeAttribute)()
                sb.AppendFormat(CultureInfo.CurrentCulture, "                Dim policy As New System.Runtime.Caching.CacheItemPolicy() With {{.AbsoluteExpiration = System.DateTimeOffset.Now.AddMinutes({0})}}", cacheTime.TimeSpan.TotalMinutes).AppendLine()
            Else
                If method.Method.HasAttribute(Of Attributes.MethodCacheTimeAttribute)() Then
                    Dim cacheTime As Attributes.MethodCacheTimeAttribute = method.Method.GetAttribute(Of Attributes.MethodCacheTimeAttribute)()
                    sb.AppendFormat(CultureInfo.CurrentCulture, "                Dim policy As New System.Runtime.Caching.CacheItemPolicy() With {{.AbsoluteExpiration = System.DateTimeOffset.Now.AddMinutes({0})}}", cacheTime.TimeSpan.TotalMinutes).AppendLine()
                Else
                    sb.AppendFormat(CultureInfo.CurrentCulture, "                Dim policy As New System.Runtime.Caching.CacheItemPolicy() With {{.AbsoluteExpiration = System.DateTimeOffset.Now.AddMinutes({0})}}", DefaultTimeSpan.TotalMinutes).AppendLine()
                End If
            End If

            sb.AppendFormat("                cacheInstance = GetInstance.{0}({1})", method.MethodName, BuildSignature(method)).AppendLine()
            sb.Append("                cache.Set(cacheName, cacheInstance, policy)").AppendLine()
            sb.Append("            End If").AppendLine()
        End Sub


        Private Sub ResetCache(ByVal method As DataObjects.MethodDefinition, ByVal sb As System.Text.StringBuilder)
            Dim resetAttribute As Attributes.CacheMethodInvalidateMethodNameAttribute = method.InstanceType.GetAttribute(Of Attributes.CacheMethodInvalidateMethodNameAttribute)()
            If resetAttribute Is Nothing Then
                resetAttribute = method.Method.GetAttribute(Of Attributes.CacheMethodInvalidateMethodNameAttribute)()
            End If
            If resetAttribute IsNot Nothing Then
                Dim methodSigCount As Integer = method.Signature.Where(Function(item) item.DoNotUseAsCacheKey = False).Count
                Dim relatedMethod As DataObjects.MethodDefinition = Methods.FirstOrDefault(Function(item)
                                                                                               Dim returning As Boolean
                                                                                               If String.Compare(item.MethodName, resetAttribute.MethodName, True) = 0 Then
                                                                                                   Dim checkSigCount As Integer = item.Signature.Where(Function(mitem) mitem.DoNotUseAsCacheKey = False).Count
                                                                                                   If checkSigCount = methodSigCount Then
                                                                                                       Dim x As Integer
                                                                                                       Dim matchCount As Integer
                                                                                                       method.Signature.Where(Function(mItem) mItem.DoNotUseAsCacheKey = False).ForEach(Sub(looker)
                                                                                                                                                                                            Dim sig As DataObjects.MethodSignature = item.Signature(x)
                                                                                                                                                                                            x += 1
                                                                                                                                                                                            If sig.Type = looker.Type Then
                                                                                                                                                                                                matchCount += 1
                                                                                                                                                                                            End If
                                                                                                                                                                                        End Sub)

                                                                                                       returning = matchCount = methodSigCount
                                                                                                   End If

                                                                                               End If
                                                                                               Return returning
                                                                                           End Function)
                If relatedMethod IsNot Nothing Then
                    sb.Append("            Dim cache As System.Runtime.Caching.ObjectCache = System.Runtime.Caching.MemoryCache.Default").AppendLine()
                    If method.Signature.Count > 0 Then
                        sb.AppendFormat(CultureInfo.CurrentCulture, "            Dim cacheName As String = {0}", BuildCacheKey(relatedMethod, relatedMethod.MethodName)).AppendLine()
                    Else
                        sb.AppendFormat("            Dim cacheName As String =""{0}{1}ConfigKey""", m_BaseType.FullName, relatedMethod.MethodName).AppendLine()
                    End If
                    sb.Append("            If cache.Contains(cacheName) Then").AppendLine()
                    sb.Append("                cache(cacheName) = Nothing").AppendLine()
                    sb.Append("            End If").AppendLine()
                Else
                    Throw New Exceptions.MethodNotFoundException(m_BaseType, resetAttribute.MethodName, method.Signature.Where(Function(item) item.DoNotUseAsCacheKey = False))
                End If

            End If
        End Sub


        Private Shared Function BuildMethodSignature(method As DataObjects.MethodDefinition) As String
            Dim signatureBuilder As New List(Of String)
            method.Signature.OrderBy(Function(oitem) oitem.Position).ForEach(Sub(sig) signatureBuilder.Add(String.Format(CultureInfo.CurrentCulture, "{0} As {1}", sig.Name, sig.Type.FullName)))
            Return String.Join(",", signatureBuilder)
        End Function

        Private Shared Function BuildWriteOnlyPropertyMethodSignature(method As DataObjects.MethodDefinition) As String
            Dim signatureBuilder As New List(Of String)
            Dim localSignature As New List(Of DataObjects.MethodSignature)
            method.Signature.ForEach(Sub(item) localSignature.Add(item))
            localSignature.RemoveAt(localSignature.Count - 1)
            localSignature.OrderBy(Function(oitem) oitem.Position).ForEach(Sub(sig) signatureBuilder.Add(String.Format(CultureInfo.CurrentCulture, "{0} As {1}", sig.Name, sig.Type.FullName)))
            Return String.Join(",", signatureBuilder)
        End Function

        Private Shared Function BuildSignature(method As DataObjects.MethodDefinition) As String
            Dim signatureBuilder As New List(Of String)
            method.Signature.OrderBy(Function(oitem) oitem.Position).ForEach(Sub(sig) signatureBuilder.Add(String.Format(CultureInfo.CurrentCulture, "{0}", sig.Name)))
            Return String.Join(",", signatureBuilder)
        End Function

        Private Shared Function BuildWriteOnlyPropertySignature(method As DataObjects.MethodDefinition) As String
            Dim signatureBuilder As New List(Of String)
            Dim localSignature As New List(Of DataObjects.MethodSignature)
            method.Signature.ForEach(Sub(item) localSignature.Add(item))
            localSignature.RemoveAt(localSignature.Count - 1)
            localSignature.OrderBy(Function(oitem) oitem.Position).ForEach(Sub(sig) signatureBuilder.Add(String.Format(CultureInfo.CurrentCulture, "{0}", sig.Name)))
            Return String.Join(",", signatureBuilder)
        End Function



        Private Function BuildCacheKey(method As DataObjects.MethodDefinition, forMethod As String) As String
            Dim sb As New System.Text.StringBuilder()
            sb.AppendFormat("String.Format(""{0}{2}Cache{1}", m_BaseType.FullName, method.ReturnType.Name, forMethod)
            Dim index As Integer
            For x As Integer = 0 To method.Signature.Count - 1
                If method.IsProperty And method.CanWrite And Not method.CanWrite Then

                    If Not method.Signature(x).DoNotUseAsCacheKey And x < method.Signature.Count - 1 Then
                        sb.AppendFormat(CultureInfo.CurrentCulture, "{{0}}", index)
                        index += 1
                    End If
                Else
                    If Not method.Signature(x).DoNotUseAsCacheKey Then
                        sb.AppendFormat(CultureInfo.CurrentCulture, "{{0}}", index)
                        index += 1
                    End If
                End If


            Next
            sb.Append(""",")
            Dim signatureBuilder As New List(Of String)
            method.Signature.Where(Function(item) Not item.DoNotUseAsCacheKey).OrderBy(Function(oitem) oitem.Position).ForEach(Sub(sig)
                                                                                                                                   If Not String.IsNullOrWhiteSpace(sig.MethodOrPropertyToUseAsCacheKey) Then
                                                                                                                                       signatureBuilder.Add(String.Format(CultureInfo.CurrentCulture, "{0}.{1}", sig.Name, sig.MethodOrPropertyToUseAsCacheKey))
                                                                                                                                   Else
                                                                                                                                       signatureBuilder.Add(String.Format(CultureInfo.CurrentCulture, "{0}", sig.Name))
                                                                                                                                   End If

                                                                                                                               End Sub)
            sb.Append(String.Join(",", signatureBuilder))
            sb.Append(")")
            Return sb.ToString
        End Function

#Region " Non Cache Methods "


        Private Function GetFunction(method As DataObjects.MethodDefinition) As String
            Dim sb As New System.Text.StringBuilder
            sb.AppendFormat("        Public Function {1}({3}) As {2} Implements {0}.{1}", m_BaseType.FullName, method.MethodName, method.ReturnType.Name, BuildMethodSignature(method)).AppendLine()
            sb.AppendFormat("            Return GetInstance.{0}({1})", method.MethodName, BuildSignature(method)).AppendLine()
            sb.Append("        End Function").AppendLine()
            Return sb.ToString
        End Function

        Private Function GetSub(method As DataObjects.MethodDefinition) As String
            Dim sb As New System.Text.StringBuilder
            sb.AppendFormat("        Public Sub {1}({2}) Implements {0}.{1}", m_BaseType.FullName, method.MethodName, BuildMethodSignature(method)).AppendLine()
            sb.AppendFormat("            GetInstance.{0}({1})", method.MethodName, BuildSignature(method)).AppendLine()
            ResetCache(method, sb)
            sb.Append("        End Sub").AppendLine()
            Return sb.ToString
        End Function


        Private Function BuildMethodProperty(method As DataObjects.MethodDefinition) As String
            Dim sb As New System.Text.StringBuilder

            If method.CanRead And method.CanWrite Then
                sb.AppendFormat("        Public Property {1}({3}) As {2} Implements {0}.{1}", m_BaseType.FullName, method.MethodName, method.ReturnType.Name, BuildMethodSignature(method)).AppendLine()

                sb.Append("            Get").AppendLine()
                sb.AppendFormat("            Return GetInstance.{0}({1})", method.MethodName, BuildSignature(method)).AppendLine()
                sb.Append("            End Get").AppendLine()

                sb.AppendFormat(CultureInfo.CurrentCulture, "            Set(value As {0})", method.ReturnType.Name).AppendLine()
                sb.AppendFormat("                GetInstance.{0}({1}) = Value", method.MethodName, BuildSignature(method)).AppendLine()
                ResetCache(method, sb)
                sb.Append("            End Set").AppendLine()

                sb.Append("        End Property").AppendLine()
            Else
                If method.CanWrite Then

                    sb.AppendFormat("        Public WriteOnly Property {1}({3}) As {2} Implements {0}.{1}", m_BaseType.FullName, method.MethodName, method.Signature(0).Type.FullName, BuildWriteOnlyPropertyMethodSignature(method)).AppendLine()

                    sb.AppendFormat("            Set(value As {0})", method.Signature(0).Type.FullName).AppendLine()
                    sb.AppendFormat("                GetInstance.{0}({1}) = Value", method.MethodName, BuildWriteOnlyPropertySignature(method)).AppendLine()
                    ResetCache(method, sb)
                    sb.Append("            End Set").AppendLine()

                    sb.Append("        End Property").AppendLine()
                Else
                    sb.AppendFormat("        Public ReadOnly Property {1}({3}) As {2} Implements {0}.{1}", m_BaseType.FullName, method.MethodName, method.ReturnType.Name, BuildMethodSignature(method)).AppendLine()

                    sb.Append("            Get").AppendLine()
                    sb.AppendFormat("            Return GetInstance.{0}({1})", method.MethodName, BuildSignature(method)).AppendLine()
                    sb.Append("            End Get").AppendLine()



                    sb.Append("            End Property").AppendLine()
                End If
            End If

            Return sb.ToString
        End Function

#End Region

        Private ReadOnly m_GeneratedType As Type
        Private ReadOnly m_SeveredInstance As Object

        ''' <summary>
        ''' Gets the object.
        ''' </summary>
        ''' <returns>System.Object.</returns>
        Public Overrides Function GetObject() As Object
            Return m_SeveredInstance
        End Function
    End Class
End Namespace
